#ifndef TASK_POOL_H
#define TASK_POOL_H
#include "utils/thread_utils.h"
#include "follower.h"
#include "utils/lock.h"
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
#include <deque>
#include <iostream>
namespace vpm
{
	namespace utils
	{
		class TaskPool
		{
			enum 
			{
				DefaultThreadNumber = 20
			};
		public:
			TaskPool()
			{
				this->m_currentThreadId = 0; 
				m_bRunning = true; 		
				for (int i = 0; i < DefaultThreadNumber ; i++)
				{
					m_thrdGroup.create_thread(boost::bind(&TaskPool::svc,this));
				}	
			}

			virtual void svc()
			{
				while (m_bRunning)
				{
					//become leader. // Block until this thread is the leader.
					this->become_leader();

					//wait on event 
					if (this->wait_event() != -1)
					{				
					}			

					this->elect_new_leader();
					//event happened , elect new leader, and process the event , I am the follower 
					this->do_work();//do my job here. 
				}
			}

			int become_leader()
			{
				Lock leaderLock(m_leaderMutex);
				if (leader_active())
				{
					//here it's a token, request for job to do. 
					bool flag = false;  
					Follower * fw  = new Follower(this->m_leaderMutex); 			
					while (leader_active())
					{					
						if (flag = !flag)
						{					
							Lock lock(m_followerMutex);				
							this->m_followers.push_back(fw); 
							m_queueCondition.signal();
						}
						fw->wait();	// wait operator will unlock the mutex first.			
					}			
					delete fw; //it's just a token , if the follower thread get work to do, delete it.  it's not safe here. 
				}

				leader_active(thread_id());
				return 0; 
			}

			Follower * make_follower()
			{	
				Follower * fw  = new Follower(this->m_leaderMutex); 
				{		
					Lock lock(m_followerMutex);				
					this->m_followers.push_back(fw); 
					m_queueCondition.signal();		
				}
				return fw; 		
			}

			bool leader_active()
			{
				return m_currentThreadId != 0;
			}

			void leader_active(const ThreadId & thrdId)
			{
				m_currentThreadId = thrdId; 
			}

			virtual int wait_event()
			{
				//here , should do the waiting job. 
				Sleep(12);
				return 0; 
			}

			int elect_new_leader()
			{
				Follower * pFollower  = NULL;
				{
					Lock lock(m_followerMutex);
					while (m_followers.empty())	
					{			
						//so , there are no follower can accept this job. 
						//should wait on the follower queue. 
						std::cout <<"Wait on emptyQueue ++++++++++++++++++++++++++++++++++++++++++++++++\n";			
						m_queueCondition.wait(m_followerMutex);
						//assert(!m_followers.empty() );
					}

					pFollower = m_followers.back();
					m_followers.pop_back();

				}
				{
					Lock leaderLock(m_leaderMutex);
					this->leader_active(0);// give up the leader 	
				}
				pFollower->signal();	

				return 0; 
			}

			void do_work()
			{
				std::cout <<"do work on thread "<< thread_id() <<std::endl; 
				Sleep(100);
				std::cout <<"finished my job"<<std::endl; 
			}
		private:
			bool m_bRunning;
			Mutex m_leaderMutex; 
			Mutex m_followerMutex; 
			Condition m_leaderCondition;
			ThreadId m_currentThreadId; 
			std::deque<Follower *> m_followers; 
			boost::thread_group m_thrdGroup;
			Condition m_queueCondition;
		};
	}
}
#endif // 